using System;

namespace DA.AnimGraph {

    public unsafe struct PerkLink : IDisposable {

        #region VirtualTable

        // Evaluate
        internal delegate void EvaluateDelegate(in void* perk, in TimeState* t, bool o, in EvaluateContext e, in GraphContext g, ref UpstreamData u, ref ScopeContext s);

        // OnExit
        internal delegate void OnExitDelegate(in void* perk, in TimeState* t, ref UpstreamData u);

        // PostEvaluate
        internal delegate void PostEvaluateDelegate(in void* perk, in TimeState* t, in EvaluateContext e, in GraphContext g, ref UpstreamData u, ref PostScopeContext p);

        #endregion

        internal PerkVirtualTable virtualFunction;
        private void* perkPtr;
        public AGRuntimeType perkType;

        internal void SetupPerk(void* perkPtr) {
            this.perkPtr = perkPtr;
        }

        internal void Evaluate(in TimeState* timeState, bool onEnter, in EvaluateContext evaluateContext, in GraphContext graphContext, ref UpstreamData upstream, ref ScopeContext scope) {
            if (virtualFunction.EvaluateFunctionPtr != null) {
                virtualFunction.EvaluateFunctionCall(perkPtr, timeState, onEnter, evaluateContext, graphContext, ref upstream, ref scope);
            }
        }

        internal void OnExit(in TimeState* timeState, ref UpstreamData upstream) {
            if (virtualFunction.OnExitFunctionPtr != null) {
                virtualFunction.OnExitFunctionCall(perkPtr, timeState, ref upstream);
            }
        }

        internal void PostEvaluate(in TimeState* timeState, in EvaluateContext evaluateContext, in GraphContext graphContext, ref UpstreamData upstream, ref PostScopeContext postScope) {
            if (virtualFunction.PostEvaluateFunctionPtr != null) {
                virtualFunction.PostEvaluateFunctionCall(perkPtr, timeState, evaluateContext, graphContext, ref upstream, ref postScope);
            }
        }

        public void Dispose() {
            perkPtr = null;
        }

        public void Dry(DryParam dryParam) {
            // 1 自己对应的perk
            DryUtility.SwitchDryNode(perkType, perkPtr, dryParam);
            // 2 自己内部数据
            DryUtility.DryPtr(ref perkPtr, dryParam);
        }

        public void Wet(DryParam dryParam) {
            virtualFunction = AGRuntimeTypeRegister.GetInstance().GetPerkVirtualTable(perkType);
            DryUtility.WetPtr(ref perkPtr, dryParam);

            DryUtility.SwitchWetNode(perkType, perkPtr, dryParam);
        }
    }
}